const path = require("path");
const fs = require("fs");

class TestData {

    constructor(filename, config, func, data) {
        this.config = config;
        this.func = func;
        this.data = data;
        if (!this.config) {
            if (fs.existsSync(path.join(process.cwd(), "src", ".config"))) {
                this.config = JSON.parse(fs.readFileSync(path.join(process.cwd(), "src", ".config"), "utf-8"));
            }
            else if (fs.existsSync(path.join(process.cwd(), "src", "config.js"))) {
                this.config = require(path.join(process.cwd(), "src", "config.js"));
                fs.writeFileSync(path.join(process.cwd(), "src", ".config"), JSON.stringify(this.config), "utf-8");
            }
            else {
                this.config = {};
            }
        }
        if (!this.func) {
            if (fs.existsSync(path.join(process.cwd(), "src", "func.js"))) {
                this.func = require(path.join(process.cwd(), "src", "func.js"));
            } else {
                this.func = {};
            }
        }
        if (!this.data) {
            if (fs.existsSync(path.join(process.cwd(), "src", "data.js"))) {
                this.data = require(path.join(process.cwd(), "src", "data.js"));
            }
            else {
                this.data = {};
            }
        }
        if (filename) {
            this.filename = path.join(process.cwd(), "src", "testdata", filename);
            this.testdata = this._createTestData(this.filename);
            this.testdata = this._analysis(this.testdata);
        }
        else {
            this.testdata = null;
        }
    }

    _createTestData(filename) {
        return JSON.parse(fs.readFileSync(filename));
    }

    _analysis(testdata) {
        let results = /^\$\{([^\${}]+)\}$/.exec(testdata);
        // 不匹配${param}
        if (results === null) {
            // 对象
            if (typeof testdata === "object" && testdata !== null) {
                Object.keys(testdata).forEach(name => {
                    testdata[name] = this._analysis(testdata[name]);
                });
            }
            // 字符串
            results = /\${[^\${}]+}/.exec(testdata); // 字符串中包含${}
            if (results !== null) {
                testdata = testdata.replace(results[0], this._analysis(results[0]));
                return this._analysis(testdata);
            }
            return testdata;
        }
        // 匹配${param}
        testdata = results[1].trim();
        results = /^([a-zA-z0-9_]+)\(([\d\D]*)\)$/.exec(testdata);
        // 不匹配method(...params), 说明是变量
        if (results === null) {
            if (testdata.startsWith("data.")) { // data.js
                testdata = testdata.substring(5); // 去除前缀data.
                try {
                    let keys = [this.data, ...testdata.split(".")];
                    return keys.reduce((previous, current) => previous[current]);
                } catch (error) {
                    throw new Error(`数据${testdata}获取失败: ${error.message}`);
                }
            } else { // config.js
                if (testdata.startsWith("config.")) {
                    testdata = testdata.substring(7); // 去除前缀config.
                }
                try {
                    let keys = [this.config, ...testdata.split(".")];
                    return keys.reduce((previous, current) => previous[current]);
                } catch (error) {
                    throw new Error(`配置${testdata}获取失败: ${error.message}`);
                }
            }
        }
        // 匹配method(...params)), 说明是方法
        let method = results[1].trim();
        let params = results[2].length === 0 ? [] : results[2].split(",").map(param => param.trim());
        params = params.map(param => {
            param = this._analysis(param);
            // 字符串
            results = /^'([\d\D]*)'|"([\d\D]*)"$/.exec(param)
            if (results !== null) {
                return results[1] || results[2];
            }
            // 数字
            results = /^([\+\-]{0,1}[0-9.]+)$/.exec(param);
            if (results !== null) {
                return Number(results[1]);
            }
            // 其他
            return param;
        });
        // 执行方法
        try {
            let f = this.func[method];
            if (!f) {
                throw new Error(`函数${method}不存在`);
            }
            testdata = f.apply(this, params);
            return testdata;
        } catch (error) {
            throw new Error(`函数${method}(${JSON.stringify(params).slice(1, -1)})执行失败: ${error.message}`);
        }
    }

}

module.exports = TestData;